﻿using System;
using System.Collections.Generic;

namespace CQRSFramework.Common.Components
{
    public interface IObjectContainer
    {
        /// <summary>Register a implementation type.
        /// </summary>
        /// <param name="implementationType">The implementation type.</param>
        /// <param name="serviceName">The service name.</param>
        /// <param name="life">The life cycle of the implementer type.</param>
        void RegisterType(Type implementationType, string serviceName = null, LifeStyle life = LifeStyle.Singleton);

        /// <summary>Register a implementer type as a service implementation.
        /// </summary>
        /// <param name="serviceType">The service type.</param>
        /// <param name="implementationType">The implementation type.</param>
        /// <param name="serviceName">The service name.</param>
        /// <param name="life">The life cycle of the implementer type.</param>
        void RegisterType(Type serviceType, Type implementationType, string serviceName = null, LifeStyle life = LifeStyle.Singleton);

        /// <summary>Register a implementer type as a service implementation.
        /// </summary>
        /// <typeparam name="TService">The service type.</typeparam>
        /// <typeparam name="TImplementer">The implementer type.</typeparam>
        /// <param name="serviceName">The service name.</param>
        /// <param name="life">The life cycle of the implementer type.</param>
        void Register<TService, TImplementer>(string serviceName = null, LifeStyle life = LifeStyle.Singleton)
            where TService : class
            where TImplementer : class, TService;

        /// <summary>Register a implementer type instance as a service implementation.
        /// </summary>
        /// <typeparam name="TService">The service type.</typeparam>
        /// <typeparam name="TImplementer">The implementer type.</typeparam>
        /// <param name="instance">The implementer type instance.</param>
        /// <param name="serviceName">The service name.</param>
        void RegisterInstance<TService, TImplementer>(TImplementer instance, string serviceName = null)
            where TService : class
            where TImplementer : class, TService;

        /// <summary>
        /// Resister Generic type
        /// </summary>
        /// <param name="serviceType"></param>
        /// <param name="implementationType"></param>
        /// <param name="serviceName"></param>
        /// <param name="life"></param>
        void RegisterGeneric(Type serviceType, Type implementationType, string serviceName = null, LifeStyle life = LifeStyle.Singleton);

        /// <summary>
        /// build the container
        /// </summary>
        void Build();

        /// <summary>
        /// Resolve a service
        /// </summary>
        /// <typeparam name="TService">The service</typeparam>
        /// <returns></returns>
        TService Resolve<TService>() where TService : class;

        /// <summary>Resolve a service.
        /// </summary>
        /// <param name="serviceType">The service type.</param>
        /// <returns>The component instance that provides the service.</returns>
        object Resolve(Type serviceType);

        /// <summary>Resolve all given service.
        /// </summary>
        /// <param name="serviceType">The given service type.</param>
        /// <returns>The all component instance that provides the service</returns>
        IEnumerable<object> ResolveAll(Type serviceType);

        /// <summary>Resolve a service or null if the service is not registed
        /// </summary>
        /// <param name="serviceType">The service type or null</param>
        /// <returns>The component instance that provides the service or null if the service is not registed</returns>
        object ResolveOptional(Type serviceType);

        /// <summary>Resolve a service.
        /// </summary>
        /// <typeparam name="TService">The service type.</typeparam>
        /// <param name="serviceName">The service name.</param>
        /// <returns>The component instance that provides the service.</returns>
        TService ResolveNamed<TService>(string serviceName) where TService : class;

        /// <summary>Resolve a service.
        /// </summary>
        /// <param name="serviceName">The service name.</param>
        /// <param name="serviceType">The service type.</param>
        /// <returns>The component instance that provides the service.</returns>
        object ResolveNamed(string serviceName, Type serviceType);
    }
}
